/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package genomemap.worker;

import javautil.lang.RandomUtil;

/**
 *
 * @author stewari1
 */
public abstract class AnnealMachine extends Worker {

    /**
     *
     */
    private static final int ORDERING_TYPE_RANDOM_BLOCK_REVERSAL = 0;

    /**
     * Simulated Annealing
     */
    public static final int MACHINE_TYPE_SIMULATED_ANNEALING = 0;

    /**
     * This is a type of Micro Canonical Annealing.
     */
    public static final int MACHINE_TYPE_RANDOM_COST = 1;

    /** Field description */
    private int orderPolicy = 0;

    /**
     * likelihood value
     */
    private double convValue = 0.0;

    /**
     *  CONVERGED ORDER
     */
    private int[] convOrder = null;

    /**
     * true: if simulated annealing has converged
     */
    private boolean converged = false;

    /**
     *
     */
    public abstract void run();

    public void setAnnealable(Annealable annealable) {

        if (this instanceof RandomCost) {

            if (!(annealable instanceof IncrementallyAnnealable)) {

                System.out.println(
                    "For AnnealMachine: RandomCost only IncrementallyAnnealable should be used");

            } else {

                IncrementallyAnnealable incrAnnealable = (IncrementallyAnnealable) annealable;
                RandomCost randomCost                  = (RandomCost) this;

                randomCost.setIncrAnnealable(incrAnnealable);
            }

        } else if (this instanceof SimulatedAnnealing) {

            SimulatedAnnealing sa = (SimulatedAnnealing) this;

            sa.setAnnealable(annealable);
        }
    }

    int[] getNewOrder(int[] oldOrder) {

        switch (orderPolicy) {

            case ORDERING_TYPE_RANDOM_BLOCK_REVERSAL :
                return RandomUtil.randomBlockReversal(oldOrder);

            default :
                return RandomUtil.randomBlockReversal(oldOrder);
        }
    }

    public int getNewOrderPolicy() {
        return orderPolicy;
    }

    /**
     *
     * @param newOrderPolicy
     */
    public void setOrderPolicy(int newOrderPolicy) {
        this.orderPolicy = newOrderPolicy;
    }

    /**
     *
     * @return
     */
    public double getConvValue() {
        return convValue;
    }

    void setConvValue(double convValue) {
        this.convValue = convValue;
    }

    public int[] getConvOrder() {
        return convOrder;
    }

    void setConvOrder(int[] convOrder) {
        this.convOrder = convOrder;
    }

    /**
     * true: if simulated annealing has converged
     * @return
     */
    public boolean isConverged() {
        return converged;
    }

    /**
     * true: if simulated annealing has converged
     *
     * @param newVal
     */
    void setConverged(boolean newVal) {
        converged = newVal;
    }
}
